rust
use std::hash::{Hash, Hasher};
use std::mem;

struct BloomFilter<T: Hash> {
    hash_func: fn(&T) -> u64,
    table: Vec<u8>,
    table_size: usize,
    num_functions: usize,
}

impl<T: Hash> BloomFilter<T> {
    fn new(table_size: usize, hash_func: fn(&T) -> u64, num_functions: usize) -> Option<Self> {
        if num_functions > Self::max_possible_functions(table_size) {
            return None;
        }

        let mut table = vec![0; table_size];
        Some(BloomFilter {
            hash_func,
            table,
            table_size,
            num_functions,
        })
    }

    fn max_possible_functions(table_size: usize) -> usize {
        table_size
    }

    fn insert(&mut self, value: &T) {
        let hash = (self.hash_func)(value);
        for i in 0..self.num_functions {
            let index = (hash ^ i as u64) % self.table_size as u64;
            self.table[index as usize / 8] |= 1 << (index as usize % 8);
        }
    }

    fn query(&self, value: &T) -> bool {
        let hash = (self.hash_func)(value);
        for i in 0..self.num_functions {
            let index = (hash ^ i as u64) % self.table_size as u64;
            if self.table[index as usize / 8] & (1 << (index as usize % 8)) == 0 {
                return false;
            }
        }
        true
    }

    fn union(filter1: &Self, filter2: &Self) -> Option<Self> {
        if filter1.table_size != filter2.table_size || filter1.num_functions != filter2.num_functions {
            return None;
        }

        let mut table = vec![0; filter1.table_size];
        for i in 0..filter1.table_size {
            table[i] = filter1.table[i] | filter2.table[i];
        }

        Some(BloomFilter {
            hash_func: filter1.hash_func,
            table,
            table_size: filter1.table_size,
            num_functions: filter1.num_functions,
        })
    }

    fn intersection(filter1: &Self, filter2: &Self) -> Option<Self> {
        if filter1.table_size != filter2.table_size || filter1.num_functions != filter2.num_functions {
            return None;
        }

        let mut table = vec![0; filter1.table_size];
        for i in 0..filter1.table_size {
            table[i] = filter1.table[i] & filter2.table[i];
        }

        Some(BloomFilter {
            hash_func: filter1.hash_func,
            table,
            table_size: filter1.table_size,
            num_functions: filter1.num_functions,
        })
    }
}

impl<T: Hash> Drop for BloomFilter<T> {
    fn drop(&mut self) {
        // Memory is automatically freed when the instance goes out of scope.
    }
}

